package com.literature.search.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.literature.search.core.common.MessageConstant;
import com.literature.search.core.common.UserInfoConstant;
import com.literature.search.core.config.satoken.RoleEnum;
import com.literature.search.core.entity.R.AjaxError;
import com.literature.search.core.entity.R.AjaxJson;
import com.literature.search.core.entity.User;
import com.literature.search.core.entity.dto.BasePageDTO;
import com.literature.search.core.utils.EncodeUtil;
import com.literature.search.core.utils.ObjectUtil;
import com.literature.search.core.utils.so.SoMap;
import com.literature.search.core.utils.sp.SpUserUtil;
import com.literature.search.user.dto.LoginUserDTO;
import com.literature.search.user.dto.RegistryUserDTO;
import com.literature.search.user.dto.UserDTO;
import com.literature.search.user.service.IUserService;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.result.UpdateResult;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;


/**
 * @Author: DangKong
 * @Date: 2023/3/2 00:27
 * @Description:
 */

@Service
public class UserServiceImpl implements IUserService {

    static final Map<String, String> fieldRegx = new HashMap<>(8);

    static {
        // 1-64个数字字母下划线
        fieldRegx.put("password", "^[0-9a-z_]{1,64}$");
        fieldRegx.put("phone", "/^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$/");
        fieldRegx.put("mail", "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$");
        // 1-140个任意字符
        fieldRegx.put("description", "(.*){1,140}");
    }

    public static final String USERNAME = "user_name"; // 用户名
    private static final String COLLECTION_NAME = "user"; // 集合名称: user
    private static final String PASSWORD = "password"; // 密码
    private static final String PHONE = "phone"; // 电话
    private static final String MAIL = "mail"; // 邮箱

    private static final String SEX = "sex"; // 性别
    private static final String AVATAR = "avatar";//头像
    private static final String UPDATE_DATE = "update_date";//头像

    @Resource
    MongoTemplate mongoTemplate;

    @Resource
    GridFsTemplate gridFsTemplate;

    @Resource
    IUserService userService;

    @Resource
    private GridFSBucket gridFsBucket;

    @Override
    public AjaxJson login(LoginUserDTO userDTO) {
        Query query = new Query(Criteria.where(USERNAME).is(userDTO.getUsername()));
        User dbUser = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
        if (dbUser == null) {
            return AjaxJson.getError(MessageConstant.USER_NOT_EXIST);
        }
        if (!dbUser.getPassword().equals(EncodeUtil.getEncodePassword(userDTO.getPassword()))) {
            return AjaxJson.getError(MessageConstant.USER_PASSWORD_ERROR);
        }

        // 屏蔽用户禁止访问
        if (Boolean.TRUE.equals(dbUser.getBanning())) {
            return AjaxJson.getError(MessageConstant.USER_HAS_BANNED);
        }
        // =========== 至此, 已登录成功 ==========
        StpUtil.login(dbUser.getId());
        // 返回登录成功的用户信息
        SoMap map = new SoMap();
        map.put("userInfo", dbUser);
        map.put("token", StpUtil.getTokenValue());
        return AjaxJson.getSuccessData(map);
    }
    @Override
    public User register(RegistryUserDTO userDTO) {
        User user = new User();
        Query query = new Query(Criteria.where(USERNAME).is(userDTO.getUsername()));
        User ifUserExist = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
        if (ifUserExist != null) {
            throw AjaxError.get(MessageConstant.USER_EXIST);
        }
        user.setRoleId(RoleEnum.USER.getCode()); // 默认注册用户为普通用户
        user.setUserName(userDTO.getUsername());
        user.setPassword(EncodeUtil.getEncodePassword(userDTO.getPassword()));
        user.setMail(userDTO.getMail());
        user.setAvatar(UserInfoConstant.DEFAULT_AVATAR); // 默认头像
        // 设置创建时间和更新时间 格式为yyyy-MM-dd HH:mm:ss
        user.setCreateDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        user.setUpdateDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return mongoTemplate.save(user, COLLECTION_NAME);
    }

    @Override
    public AjaxJson getUserInfoById(String userId) {
        Query query = new Query(Criteria.where("_id").is(userId));
        User dbUser = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
        if (dbUser != null) {
            return AjaxJson.getSuccessData(dbUser);
        }
        return null;
    }

    @Override
    public AjaxJson updateUserInfo(UserDTO userDTO) {

        if (StringUtils.hasText(userDTO.getPassword())) {
            if (!patternMatch(userDTO.getPassword(), fieldRegx.get("password"))) {
                return AjaxJson.get(MessageConstant.PARAMS_ERROR_CODE, MessageConstant.PARAMS_FORMAT_ERROR);
            }
        }
        if (StringUtils.hasText(userDTO.getMail())) {
            if (!patternMatch(userDTO.getMail(), fieldRegx.get("mail"))) {
                return AjaxJson.get(MessageConstant.PARAMS_ERROR_CODE, MessageConstant.PARAMS_FORMAT_ERROR);
            }
        }
        if (StringUtils.hasText(userDTO.getPhone())) {
            if (!patternMatch(userDTO.getPhone(), fieldRegx.get("phone"))) {
                return AjaxJson.get(MessageConstant.PARAMS_ERROR_CODE, MessageConstant.PARAMS_FORMAT_ERROR);
            }
        }

        String userId = SpUserUtil.getCurrUser().getUserName();
        if(!ObjectUtil.checkObjFieldsIsNotNull(userDTO,null)) {
            return AjaxJson.getError(MessageConstant.PARAMS_FORMAT_ERROR);
        }
        Query query = new Query(Criteria.where("_id").is(userId));
        User user = mongoTemplate.findOne(query, User.class,COLLECTION_NAME);
        Base64.Decoder decoder = Base64.getDecoder();
        String password = new String(decoder.decode(userDTO.getPassword()));
        Update update = new Update();
        if (user.getPassword() != password){
            password = EncodeUtil.getEncodePassword(password);
            update.set(PASSWORD,password);
        }
        update.set(USERNAME,userDTO.getUserName());
        update.set(PHONE, userDTO.getPhone());
        update.set(MAIL, userDTO.getMail());
        update.set(SEX, userDTO.getSex());
        mongoTemplate.updateFirst(query, update, User.class);
        return AjaxJson.getSuccess(MessageConstant.SUCCESS);
    }


    private boolean patternMatch(String s, String regex) {
        return Pattern.compile(regex).matcher(s).matches();
    }


    @Override
    public AjaxJson changeAvatar(MultipartFile file) {
        // 获取当前用户
        User user = SpUserUtil.getCurrUser();
        String userId = user.getId();
        //获取当前用户的头像gridfsId
        String originAvatarId = user.getAvatar();

        String newAvatarId;
        try {
            newAvatarId = userService.uploadAvatarToGridFs(file.getOriginalFilename(), file.getInputStream(), file.getContentType());
        } catch (IOException e) {
            return AjaxJson.getError(MessageConstant.OPERATE_FAILED);
        }
        Query query = new Query().addCriteria(Criteria.where("_id").is(userId));
        Update update = new Update();
        update.set(AVATAR,newAvatarId);
        update.set(UPDATE_DATE, new Date());
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, COLLECTION_NAME);

        // 删除原来的头像
        if (StringUtils.hasText(originAvatarId)) {
            Query gridQuery = new Query().addCriteria(Criteria.where("_id").is(originAvatarId));
            gridFsTemplate.delete(gridQuery);
        }
        return AjaxJson.getByLine((int) updateResult.getModifiedCount());

    }

    @Override
    public String uploadAvatarToGridFs(String prefix, InputStream in, String contentType) {
        String gridfsId = prefix + IdUtil.simpleUUID();
        ObjectId objectId = gridFsTemplate.store(in, gridfsId, contentType);
        return objectId.toString();
    }

    @Override
    public byte[] getAvatarBytes(String avatar) {
        if (StringUtils.hasText(avatar)) {
            Query gridQuery = new Query().addCriteria(Criteria.where("_id").is(avatar));
            GridFSFile fsFile = gridFsTemplate.findOne(gridQuery);
            if (fsFile == null) {
                System.out.println("图片为空");
                return new byte[0];
            }
            try (GridFSDownloadStream in = gridFsBucket.openDownloadStream(fsFile.getObjectId())) {
                if (in.getGridFSFile().getLength() > 0) {
                    GridFsResource resource = new GridFsResource(fsFile, in);
                    return IoUtil.readBytes(resource.getInputStream());
                } else {
                    return new byte[0];
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return new byte[0];
    }

    @Override
    public AjaxJson getUserListByPage(BasePageDTO page) {
        long count = mongoTemplate.count(new Query(),User.class,COLLECTION_NAME);
        if (count < 1) {
            return AjaxJson.getError(MessageConstant.DATA_IS_NULL);
        }
        int pageNum = Optional.ofNullable(page.getPage()).orElse(1);
        int pageSize = Optional.ofNullable(page.getRows()).orElse(10);
        // 如果传入的参数超过了总数，返回第一页
        if ((long) (pageNum - 1) * pageSize > count) {
            pageNum = 1;
        }
        Query query = new Query();
        query.skip((long) (pageNum - 1) * pageSize);
        query.limit(pageSize);
        List<User> users = mongoTemplate.find(query, User.class,COLLECTION_NAME);
        SoMap map = new SoMap();
        map.put("total", count);
        map.put("pageNum", pageNum);
        map.put("pageSize", pageSize);
        map.put("result", users);
        return AjaxJson.getSuccessData(map);
    }

    @Override
    public AjaxJson registerAdmin(RegistryUserDTO user) {
        User temp = register(user);
        temp.setRoleId(RoleEnum.ADMIN.getCode());
        //更新用户角色
        Query query = new Query(Criteria.where("_id").is(temp.getId()));
        Update update = new Update();
        update.set("roleId",temp.getRoleId());
        mongoTemplate.updateFirst(query,update,User.class,COLLECTION_NAME);
        return AjaxJson.getSuccess(MessageConstant.SUCCESS);
    }

    @Override
    public AjaxJson blockUser(List<String> userIds) {
        if(userIds == null){
            return AjaxJson.getError(MessageConstant.PARAMS_FORMAT_ERROR);
        }
        Query query = new Query(Criteria.where("_id").in(userIds));
        Update update = new Update();
        update.set("banning",true);
        UpdateResult updateResult = mongoTemplate.updateMulti(query,update, User.class,COLLECTION_NAME);
        long matchedCount = updateResult.getMatchedCount();
        if (matchedCount > 0) {
            return AjaxJson.getSuccess(MessageConstant.SUCCESS);
        }
        return AjaxJson.getError(MessageConstant.OPERATE_FAILED);
    }


}
